﻿#ifndef FILEIO__H
#define FILEIO__H

#include <cstdio>
#include <stdexcept> // std::runtime_error

namespace HDK_PRT
{
    //! for RAII, derived from wikipedia
    class FileIO
    {
    public:
        FileIO (const char* filename, const char* mode)
            : mFile(std::fopen(filename, mode))
        {
            if (!mFile)
            {
                throw std::runtime_error("file open failure");
            }
        }

        ~FileIO()
        {
            if(mFile)
            {
                std::fclose(mFile);
            }
        }

        void
        write (const void * ptr, size_t size, size_t count)
        {
            if(std::fwrite(ptr, size, count, mFile) != count)
            {
                throw std::runtime_error("file write failure");
            }
        }

        size_t
        read (void * ptr, size_t size, size_t count)
        {
            size_t retVal = std::fread(ptr, size, count, mFile);
            if(retVal != count)
            {
                // we could have hit EOF
                throw std::runtime_error("file read failure");
            }
            return retVal;
        }

        void
        flush()
        {
            if(0 != std::fflush(mFile))
            {
                throw std::runtime_error("file flush failure");
            }
        }

        long int
        tell()
        {
            long int retVal = std::ftell(mFile);
            if(retVal == -1L)
            {
                throw std::runtime_error("ftell failure");
            }
            return retVal;
        }

        int
        seek(long int offset, int origin)
        {
            int retVal = std::fseek(mFile, offset, origin);
            if(retVal != 0)
            {
                throw std::runtime_error("fseek failure");
            }
            return retVal;
        }

    private:
        std::FILE* mFile;

        // prevent copying and assignment; not implemented
        FileIO (const FileIO &);
        FileIO & operator= (const FileIO &);
    };
}

#endif
